package com.stone.framework.user.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stone.framework.message.user.PermissionReqBody;
import com.stone.framework.message.user.PermissionResBody;
import com.stone.framework.message.user.PermissionTreeResBody;
import com.stone.framework.user.entity.RoleResource;
import com.stone.framework.user.mapper.PermissionMapper;
import com.stone.framework.user.service.PermissionService;
import com.stone.framework.user.service.RoleUserService;
import com.stone.framework.user.service.UserService;

@Service
@Transactional(readOnly = true)
public class PermissionServiceImpl extends ServiceImpl<BaseMapper<RoleResource>, RoleResource>
    implements PermissionService {

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private RoleUserService roleUserService;

    @Autowired
    private UserService userService;

    @Override
    public PermissionResBody buildTree(Long roleId) {
        List<Map<String, Object>> list = this.queryByRoleId(roleId);
        List<PermissionTreeResBody> tree = list.stream().filter(perm -> (perm.get("PARENT_ID")).equals(0))
            .map(perm -> this.doBuildTree(perm, list)).collect(Collectors.toList());

        List<Long> perms = new ArrayList<>();
        tree.stream().forEach(e -> this.buildPermList(e, perms));
        PermissionResBody resBody = new PermissionResBody();
        resBody.setTree(tree);
        resBody.setList(perms);
        return resBody;
    }

    @Override
    @Transactional(readOnly = false)
    public void save(PermissionReqBody reqBody) {
        // TODO 全量处理，后期可与前端协商只处理变更数据
        List<Long> update = reqBody.getResourceIds();
        List<Long> current =
            permissionMapper.selectList(new QueryWrapper<RoleResource>().eq("role_id", reqBody.getRoleId()))
                .parallelStream().map(RoleResource::getResourceId).collect(Collectors.toList());

        this.delete(current, update, reqBody.getRoleId());
        this.insert(current, update, reqBody.getRoleId());

        CompletableFuture.runAsync(() -> this.refresh(reqBody.getRoleId()));
    }

    @Override
    public List<String> queryByUsername(String username) {
        return permissionMapper.selectByUsername(username).stream().map(map -> map.get("NAME").toString()).distinct()
            .collect(Collectors.toList());
    }

    private void refresh(Long roleId) {
        List<Long> userIdList = this.roleUserService.queryByRoleId(roleId);
        this.userService.refresh(userIdList);
    }

    private List<Map<String, Object>> queryByRoleId(Long roleId) {
        return permissionMapper.selectByRoleId(roleId);
    }

    private void delete(List<Long> current, List<Long> update, Long roleId) {
        Set<Long> currentTemp = new HashSet<>(current);
        Set<Long> updateTemp = new HashSet<>(update);
        currentTemp.removeAll(updateTemp);
        if (!currentTemp.isEmpty()) {
            this.remove(new QueryWrapper<RoleResource>().eq("role_id", roleId).in("resource_id", currentTemp));
        }
    }

    private void insert(List<Long> current, List<Long> update, Long roleId) {
        Set<Long> currentTemp = new HashSet<>(current);
        Set<Long> updateTemp = new HashSet<>(update);
        updateTemp.removeAll(currentTemp);
        List<RoleResource> list = updateTemp.stream().map(e -> {
            RoleResource rr = new RoleResource();
            rr.setRoleId(roleId);
            rr.setResourceId(e);
            return rr;
        }).collect(Collectors.toList());
        this.saveBatch(list);
    }

    private PermissionTreeResBody doBuildTree(Map<String, Object> root, List<Map<String, Object>> list) {
        List<PermissionTreeResBody> children =
            list.stream().filter(node -> root.get("ID").equals(node.get("PARENT_ID"))).map(node -> {
                PermissionTreeResBody child = this.doBuildTree(node, list);

                child.setId(((Integer)node.get("ID")).longValue());
                child.setName((String)node.get("NAME"));
                child.setDesc((String)node.get("DESC_"));
                child.setOrder((Integer)node.get("ORDER_"));
                child.setGranted((String)node.get("GRANTED"));
                return child;
            }).sorted((o1, o2) -> o1.getOrder() - o2.getOrder()).collect(Collectors.toList());

        PermissionTreeResBody resBody = new PermissionTreeResBody();

        resBody.setId(((Integer)root.get("ID")).longValue());
        resBody.setName((String)root.get("NAME"));
        resBody.setDesc((String)root.get("DESC_"));
        resBody.setOrder((Integer)root.get("ORDER_"));
        resBody.setGranted((String)root.get("GRANTED"));
        resBody.setChildren(children);
        return resBody;
    }

    /**
     * 只保留叶子节点
     * 
     * @param tree
     * @param result
     */
    private void buildPermList(PermissionTreeResBody tree, List<Long> result) {
        if ("Y".equals(tree.getGranted()) && tree.getChildren().isEmpty()) {
            result.add(tree.getId());
        } else if (!tree.getChildren().isEmpty()) {
            tree.getChildren().stream().forEach(body -> this.buildPermList(body, result));
        }
    }

}
